// Original C++ solution (slower):
#include<iostream>

#include<algorithm>

#include<iomanip>

#include<cmath>

#include<vector>

#include<queue>

#include<stack>

#include<set>

#include <cstdio>

#include<map>

#include<string>

#include<assert.h>

#include<unordered_map>

#include <cstring>//memset();

#define Amr_Abdelazim ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);

#define pb push_back

#define pp pop_back

#define ll long long

#define ld long double

#define pll pair<ll,ll> 

#define vll vector<ll> 

#define vvll vector<vector<ll> >  

#define vpll vector<pair<ll,ll> > 

#define all(v) v.begin(),v.end()

#define rep(i,n)   for(int i=0;i<n;i++)

#define repp(s,i,n)   for(int i=s;i<n;i++)

#define print(v) for(auto i:v)cout<<i<<" ";cout<<"\n"; 

#define mkp make_pair

#define clr(ar,v) memset(ar,v,sizeof(ar));

#define TC ll t;cin>>t;while(t--)

#define in_vec ll n;cin>>n;vll v(n);rep(i,n)cin >> v[i];

#define EPS 1e-9

using namespace std;

const int mod = 1000000007;

const int N = 1000005;

class cmp{

public:

	bool operator() (pair<ll, pll> &A, pair<ll, pll> &B){

		return A > B;

	}

};

bool by_sec(pll &A, pll &B){

	return A.second < B.second;

}

bool is(pll a, pll b){

	return !((a.first > b.second&&a.second > b.second) || (a.first < b.first&&a.second < b.first));

}

ld dist(pll p1, pll p2){

	return (ld)sqrt((ld)(p1.first - p2.first)*(p1.first - p2.first) + (ld)(p1.second - p2.second)*(p1.second - p2.second));

}

vvll vv(100000+9);

ll dp[100000 + 9];

ll path(ll n){

	if (vv[n].size() == 0)return 0;

	if (dp[n] == -1){

		ll mx = -1;

		rep(i, vv[n].size())mx = max(mx, path(vv[n][i])+1);

		dp[n] = mx;

	}

	return dp[n];

}

int main()

{

	Amr_Abdelazim

		clr(dp, -1);

		ll n, m,ans=0;

	cin >> n >> m;

	while (m--){

		ll a, b;

		cin >> a >> b;

		vv[a].push_back(b);

	}

	repp(1, i, n + 1)

		ans = max(ans, path(i));

	cout << ans << "\n";

	return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

#define eps 1e-3

#define pi acos(-1.0)

#define inf 0x3f

#define INF 0x3f3f3f3f

#define pb push_back

#define debug1 cout<<"&&";

#define debug2 cout<<"**";

#define ms(a, x) memset(a, x, sizeof(a))

#define for0(i, n) for(int i = 0; i < n; ++i)

#define for1(i, n) for(int i = 1; i <= n; ++i)

using namespace std;

typedef double db;

typedef long long ll;

typedef unsigned long long ull;

typedef pair<int, int> pii;

typedef pair<long long, int> pli;

typedef pair<long long, long long> pll;

const int mod = 1e9 + 7;

const int N = 1e5+10;

const int M = 1e6+10;

inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }

inline ll Pow(ll a, ll b) { ll ans = 1; for( ; b; b >>= 1) { if(b&1) ans = ans * a % mod; a = a * a % mod;} return ans;}

inline ll Mul ( ll a, ll b)  { ll lf = a * ( b >> 25ll ) % mod * ( 1LL << 25 ) % mod; ll rg = a * ( b & ( ( 1ll << 25 ) - 1 ) ) % mod; return ( lf + rg ) % mod;}

inline ll C(ll y, ll x) { ll ans = 1; if(y < 0 || x < 0 || y < x) return 0; y %= mod; if(!y || !x) return 1; for0(i, x) ans = ans * (y-i) % mod; for1(i, x) ans = ans * Pow(i, mod-2) % mod; return ans; }

//==================================================================================================================================================================//



int n, m, tot, head[N], nex[N], ver[N];

int dp[N], deg[N], ans;

queue<int> q;



void add(int x, int y) {

   ver[++tot] = y, nex[tot] = head[x], head[x] = tot;

}



int main() {

   scanf("%d %d", &n, &m);

   for1(i, m) {

      int x, y;

      scanf("%d %d", &x, &y);

      add(x, y);

      deg[y]++;

   }

   for1(i, n) if(!deg[i]) q.push(i);

   while(!q.empty()) {

      int x = q.front(); q.pop();

      for(int i = head[x]; i; i = nex[i]) {

         int y = ver[i]; deg[y]--;

         dp[y] = max(dp[y], dp[x] + 1);

         if(!deg[y]) q.push(y);

      }

   }

   for1(i, n) ans = max(ans, dp[i]);

   printf("%d\n", ans);

   return 0;

}

// Fastest known solution for this problem: